/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package technotheist.imgcog.filter;

import com.amd.aparapi.Kernel;
import com.amd.aparapi.Range;
import technotheist.imgcog.image.ImagePtr;
import technotheist.imgcog.image.ImageTemplate;

/**
 *
 * @author Mitch
 */
public abstract class Filter {
    private ImageTemplate inputTemplate;
    private ImageTemplate outputTemplate;

    private final Range range;
    private final FilterRunner runner;

    protected Filter(FilterRunner runner) {
        this.runner = runner;
        this.range = Range.create2D(runner.imgWidth, runner.imgHeight);
    }

    protected FilterRunner runner() {
        return runner;
    }

    public boolean filter(ImagePtr src, ImagePtr dst) {
        if (inputTemplate.equalTemplate(src) && outputTemplate.equalTemplate(dst)) {
            System.arraycopy(src.data(), 0, runner.input, 0, runner.size);
            runner.put(runner.input);
            runner.execute(range);
            runner.get(runner.output);
            System.arraycopy(runner.output, 0, dst.data(), 0, runner.size);
            return true;
        }
        return false;
    }

    protected static abstract class FilterRunner extends Kernel {
        protected final int imgWidth, imgHeight, imgPixSize, size;
        protected final float[] input;
        protected final float[] output;

        protected FilterRunner(int width, int height, int pixSize) {
            this.imgWidth = width;
            this.imgHeight = height;
            this.imgPixSize = pixSize;
            this.size = width * height * pixSize;
            this.input = new float[size];
            this.output = new float[size];
            this.setExplicit(true);
            put(input);
            put(output);
        }

        protected int imgIndex(int x, int y, int p) {
            return index3D(x, y, p, imgHeight, imgPixSize);
        }

        protected int index2D(int x, int y, int height) {
            return y + height * x;
        }

        protected int x2D(int index, int height) {
            return index / height;
        }

        protected int y2D(int index, int height) {
            return index % height;
        }

        protected int index3D(int x, int y, int z, int height, int pixSize) {
            return z + pixSize * (y + height * x);
        }

        protected int x3D(int index, int height, int pixSize) {
            return index / (height * pixSize);
        }

        protected int y3D(int index, int height, int pixSize) {
            return (index / pixSize)% height;
        }

        protected int z3D(int index, int pixSize) {
            return index % pixSize;
        }
    }
}
